package com.chinasofti.seckill.service.impl;

import com.alibaba.fastjson.JSON;
import com.chinasofti.seckill.bo.SeatsBO;
import com.chinasofti.seckill.bo.SeckillBO;
import com.chinasofti.seckill.bo.SessionBO;
import com.chinasofti.seckill.service.SeckillService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @description:
 * @author: wei-xhh
 * @create: 2020-08-01
 */
@Slf4j
@Service
public class SeckillServiceImpl implements SeckillService {

    private final String SKUKILL_CACHE_PREFIX = "session:seat:";

    private final String SESSION_COUNT = "session:count:";

    private final String SEMAPHORE_COUNT = "session:semaphore:";

    private final String SKU_STOCK_SEMAPHORE = "seckill:seatsCount:"; //加+考场id

    private final String SESSION_ID="1";

    @Autowired
    RedissonClient redissonClient;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Override
    public void initSessionWithSeats() {

        BoundHashOperations<String, Object, Object> ops = redisTemplate.boundHashOps(SKUKILL_CACHE_PREFIX+SESSION_ID);

        redisTemplate.opsForValue().set(SESSION_COUNT+SESSION_ID,"100");

        SessionBO sessionBO = new SessionBO();
        sessionBO.setId(1);
        ArrayList<SeatsBO> seatsBOS = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            SeatsBO seatsBO = new SeatsBO();
            seatsBO.setNo(i);
            seatsBOS.add(seatsBO);
        }
        sessionBO.setSeatsBOS(seatsBOS);

        String jsonString = JSON.toJSONString(sessionBO);

        if(!ops.hasKey(SESSION_ID)){
            ops.put(SESSION_ID, jsonString);
        }
        RSemaphore semaphore = redissonClient.getSemaphore(SKU_STOCK_SEMAPHORE + SESSION_ID);
        //semaphore.trySetPermits(sessionBO.getSeatsBOS().size());
        semaphore.trySetPermits(2);

        //-Xms256m -Xmx512m
        RSemaphore semaphoreCount = redissonClient.getSemaphore(SEMAPHORE_COUNT + SESSION_ID);
        //semaphore.trySetPermits(sessionBO.getSeatsBOS().size());
        semaphoreCount.trySetPermits(40);
    }

    @Override
    public void clearSessionWithSeats() {
        redisTemplate.opsForValue().set(SESSION_COUNT+SESSION_ID,"0");
        BoundHashOperations<String, Object, Object> seat = redisTemplate.boundHashOps(SKUKILL_CACHE_PREFIX+SESSION_ID);

        BoundHashOperations<String, Object, Object> count = redisTemplate.boundHashOps(SKU_STOCK_SEMAPHORE + SESSION_ID);
        if(seat.hasKey(SESSION_ID)){
            seat.delete(SESSION_ID);

        }
        redisTemplate.delete(SKU_STOCK_SEMAPHORE + SESSION_ID);
        redisTemplate.delete(SEMAPHORE_COUNT + SESSION_ID);
    }

    @Override
    public void kill() {
        //-Xms256m -Xmx512m
        RLock killLock = this.redissonClient.getLock("kill");
        killLock.lock(5,TimeUnit.SECONDS);
        BoundHashOperations<String, Object, Object> ops = redisTemplate.boundHashOps(SKUKILL_CACHE_PREFIX+SESSION_ID);

        long start = System.currentTimeMillis();
        //构造一个用户
        UUID uuid = UUID.randomUUID();
        BoundHashOperations<String, Object, Object> hashOps = redisTemplate.boundHashOps(SKUKILL_CACHE_PREFIX+SESSION_ID);

        SessionBO sessionBO = JSON.parseObject(hashOps.get(SESSION_ID).toString(), SessionBO.class);

      //  System.out.println(sessionBO);
        List<SeatsBO> seatsBOS = sessionBO.getSeatsBOS();


        RSemaphore semaphore = redissonClient.getSemaphore(SKU_STOCK_SEMAPHORE + SESSION_ID);
        boolean b = semaphore.tryAcquire(1);

        if(b){
            for (SeatsBO seat:seatsBOS) {
                if(seat.getIsEmpty()){
                    seat.setIsEmpty(false);
                    seat.setIsBy(uuid.toString());
                    //log.info("秒杀成功!座位号: "+seat.getNo()+"身份证: "+uuid.toString());
                    break;
                }
            }
            String jsonString = JSON.toJSONString(sessionBO);
            ops.put(SESSION_ID, jsonString);
        }

        long end = System.currentTimeMillis();
       // log.info("共耗时"+(end-start)+"毫秒");
        killLock.unlock();
    }

    @Override
    public String killFast() {
        RSemaphore semaphore = redissonClient.getSemaphore(SEMAPHORE_COUNT + SESSION_ID);
        if(semaphore.tryAcquire(1)){
            String seatNo = this.redisTemplate.opsForValue().get(SEMAPHORE_COUNT + SESSION_ID);
            //this.redisTemplate.opsForValue().set(SESSION_COUNT+SESSION_ID,String.valueOf(--count));
            SeckillBO seckillBO = new SeckillBO();
            seckillBO.setSeatNo(Integer.valueOf(seatNo));
            String idCard=UUID.randomUUID().toString();
            seckillBO.setCard(idCard);
            seckillBO.setSessionID(Integer.parseInt(SESSION_ID));
            log.info("秒杀人:"+idCard+"考场号:"+SESSION_ID+"座位号:"+seatNo);
            //这里可以用rabbitmq发送消息
            return "恭喜秒杀成功!";
        }
        //log.info("没有座位了");
        return "失败";
    }
}
